1   /*
2    * Copyright (C) 2009 The Guava Authors
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package com.google.common.util.concurrent;
18  
19  import static com.google.common.base.Preconditions.checkNotNull;
20  
21  import com.google.common.base.Supplier;
22  
23  import java.util.concurrent.Callable;
24  
25  import javax.annotation.Nullable;
26  
27  /**
28   * Static utility methods pertaining to the {@link Callable} interface.
29   *
30   * @author Isaac Shum
31   * @since 1.0
32   */
33  public final class Callables {
34    private Callables() {}
35  
36    /**
37     * Creates a {@code Callable} which immediately returns a preset value each
38     * time it is called.
39     */
40    public static <T> Callable<T> returning(final @Nullable T value) {
41      return new Callable<T>() {
42        @Override public T call() {
43          return value;
44        }
45      };
46    }
47  
48    /**
49     * Wraps the given callable such that for the duration of {@link Callable#call} the thread that is
50     * running will have the given name.
51     *
52     *
53     * @param callable The callable to wrap
54     * @param nameSupplier The supplier of thread names, {@link Supplier#get get} will be called once
55     *     for each invocation of the wrapped callable.
56     */
57    static <T> Callable<T> threadRenaming(final Callable<T> callable,
58        final Supplier<String> nameSupplier) {
59      checkNotNull(nameSupplier);
60      checkNotNull(callable);
61      return new Callable<T>() {
62        @Override public T call() throws Exception {
63          Thread currentThread = Thread.currentThread();
64          String oldName = currentThread.getName();
65          boolean restoreName = trySetName(nameSupplier.get(), currentThread);
66          try {
67            return callable.call();
68          } finally {
69            if (restoreName) {
70              trySetName(oldName, currentThread);
71            }
72          }
73        }
74      };
75    }
76  
77    /**
78     * Wraps the given runnable such that for the duration of {@link Runnable#run} the thread that is
79     * running with have the given name.
80     *
81     *
82     * @param task The Runnable to wrap
83     * @param nameSupplier The supplier of thread names, {@link Supplier#get get} will be called once
84     *     for each invocation of the wrapped callable.
85     */
86    static Runnable threadRenaming(final Runnable task, final Supplier<String> nameSupplier) {
87      checkNotNull(nameSupplier);
88      checkNotNull(task);
89      return new Runnable() {
90        @Override public void run() {
91          Thread currentThread = Thread.currentThread();
92          String oldName = currentThread.getName();
93          boolean restoreName = trySetName(nameSupplier.get(), currentThread);
94          try {
95            task.run();
96          } finally {
97            if (restoreName) {
98              trySetName(oldName, currentThread);
99            }
100         }
101       }
102     };
103   }
104 
105   /** Tries to set name of the given {@link Thread}, returns true if successful. */
106   private static boolean trySetName(final String threadName, Thread currentThread) {
107     // In AppEngine this will always fail, should we test for that explicitly using
108     // MoreExecutors.isAppEngine.  More generally, is there a way to see if we have the modifyThread
109     // permission without catching an exception?
110     try {
111       currentThread.setName(threadName);
112       return true;
113     } catch (SecurityException e) {
114       return false;
115     }
116   }
117 }